/** \file    fRGB.h
  * \brief   float per channel color.
  * \date    1998-2001
  * \author  Aloudin (Albert) Akhriev
  * \version $Header: /home/cscom1r4/cvsroot/cs/include/imglib/fRGB.h,v 1.1 2004/02/04 14:43:24 cscom1r4 Exp $
  */

#ifndef _fRGB_h_
#define _fRGB_h_

#include <math.h>
#include <float.h>
#include "bRGB.h"

namespace img {

//=================================================================================================
// 3D Color Vector.
// N O T E: Vector should have 4 (!) components to be supported by SIMD.
//=================================================================================================
struct fRGB
{
  float r, g, b, a;     // Red - Green - Blue - Alpha

  fRGB();
  fRGB(bRGB color);
  fRGB(float R, float G, float B, float A = 0.0f);
  fRGB(unsigned R, unsigned G, unsigned B, unsigned A = 0);
  void Clear() { r = g = b = a = 0.0f; }
  bool operator ==( const fRGB &x ) const { return r==x.r && g==x.g && b==x.b; }
  bool operator !=( const fRGB &x ) const { return r!=x.r || g!=x.g || b!=x.b; }

  fRGB & operator+=(const fRGB & v);
  fRGB   operator+(const fRGB & v) const;
  fRGB & operator-=(const fRGB & v);
  fRGB   operator-(const fRGB & v) const;
  fRGB & operator*=(const fRGB & v);
  fRGB   operator*(const fRGB & v) const;
  fRGB & operator/=(const fRGB & v);
  fRGB   operator/(const fRGB & v) const;

  fRGB & operator=(bRGB color);
  float  operator&(const fRGB & v) const;
  fRGB & operator*=(float coef);
  fRGB   operator*(float coef) const;

  float  Length() const;
  float  SqLength() const;
  float  SqDistance(const fRGB& x) const;
#ifdef _3DNOW
  float  SqDistance3DNow(const fRGB& x) const;
#endif

  fRGB & Set(float R, float G, float B, float A = 0.0f);
};

////////////////////////////////////////////////////////////////////////////
// Implementation.
////////////////////////////////////////////////////////////////////////////

inline fRGB::fRGB()
: r(0.0f), g(0.0f), b(0.0f), a(0.0f) 
{
}


inline fRGB::fRGB(bRGB color)
: r((float)(color.r)),
  g((float)(color.g)),
  b((float)(color.b)),
  a((float)(color.a))
{
}


inline fRGB::fRGB(float R, float G, float B, float A)
: r(R),
  g(G),
  b(B),
  a(A) 
{
}


inline fRGB::fRGB(unsigned R, unsigned G, unsigned B, unsigned A)
: r((float)R),
  g((float)G),
  b((float)B),
  a((float)A)
{
}


inline fRGB & fRGB::operator+=(const fRGB & v)
{
  r += v.r;
  g += v.g;
  b += v.b;
  return (*this);
}


inline fRGB fRGB::operator+(const fRGB & v) const
{
  return fRGB(r+v.r, g+v.g, b+v.b);
}


inline fRGB & fRGB::operator-=(const fRGB & v)
{
  r -= v.r;
  g -= v.g;
  b -= v.b;
  return (*this);
}


inline fRGB fRGB::operator-(const fRGB & v) const
{
  return fRGB(r-v.r, g-v.g, b-v.b);
}


inline fRGB & fRGB::operator*=(const fRGB & v)
{
  r *= v.r;
  g *= v.g;
  b *= v.b;
  return (*this);
}


inline fRGB fRGB::operator*(const fRGB & v) const
{
  return fRGB(r*v.r, g*v.g, b*v.b);
}


inline fRGB & fRGB::operator/=(const fRGB & v)
{
  r /= v.r;
  g /= v.g;
  b /= v.b;
  return (*this);
}


inline fRGB fRGB::operator/(const fRGB & v) const
{
  return fRGB(r/v.r, g/v.g, b/v.b);
}


inline fRGB & fRGB::operator=(bRGB color)
{
  r = (float)(color.r);
  g = (float)(color.g);
  b = (float)(color.b);
  a = (float)(color.a);
  return (*this);
}


inline float fRGB::operator&(const fRGB & v) const
{
  return (r*v.r + g*v.g + b*v.b);
}


inline fRGB & fRGB::operator*=(float coef)
{
  r *= coef;
  g *= coef;
  b *= coef;
  return (*this);
}


inline fRGB fRGB::operator*(float coef) const
{
  return fRGB(r*coef, g*coef, b*coef);
}


inline float fRGB::Length() const
{
  return (float)(sqrt(r*r + g*g + b*b));
}


inline float fRGB::SqLength() const
{
  return (r*r + g*g + b*b);
}

inline float fRGB::SqDistance(const fRGB& x) const
{
	return (sqr(r-x.r) + sqr(g-x.g) + sqr(b-x.b));
}

#ifdef _3DNOW
inline float fRGB::SqDistance3DNow(const fRGB& x) const
{
    float r;
    __asm {
        femms
        mov         eax,x
        movq        mm0,[eax]
        movd        mm1,[eax+8]
		mov			ebx,this
        movq        mm2,[ebx]
        movd        mm3,[ebx+8]
		pfsub		mm0,mm2
		pfsub		mm1,mm3
		pfmul		mm0,mm0
		pfmul		mm1,mm1
		pfadd		mm0,mm1
		pfacc		mm0,mm0
        movd        r,mm0
        femms
    }
    return r;
}
#endif

inline fRGB & fRGB::Set(float R, float G, float B, float A)
{
  r = R;
  g = G;
  b = B;
  a = A;
  return (*this);
}

} //namespace img

inline img::fRGB operator*(float coef,const img::fRGB & x) 
	{ return x*coef; }

inline img::fRGB sqr(img::fRGB x) 
	{ return x*x; }

#endif //_fRGB_h_
